package com.jerboa.ui.components.post

import android.util.Log
import androidx.compose.foundation.focusable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.ExperimentalLayoutApi
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.LazyListState
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.outlined.ArrowBack
import androidx.compose.material.icons.automirrored.outlined.Sort
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.Scaffold
import androidx.compose.material3.SnackbarHostState
import androidx.compose.material3.TopAppBar
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.material3.pulltorefresh.PullToRefreshBox
import androidx.compose.material3.rememberTopAppBarState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.input.key.Key
import androidx.compose.ui.input.key.key
import androidx.compose.ui.input.key.onKeyEvent
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.semantics.testTagsAsResourceId
import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
import arrow.core.Either
import com.jerboa.JerboaAppState
import com.jerboa.PostViewMode
import com.jerboa.R
import com.jerboa.api.ApiState
import com.jerboa.buildCommentsTree
import com.jerboa.datatypes.BanFromCommunityData
import com.jerboa.datatypes.getLocalizedCommentSortTypeName
import com.jerboa.db.entity.isAnon
import com.jerboa.feat.BlurNSFW
import com.jerboa.feat.PostActionBarMode
import com.jerboa.feat.SwipeToActionPreset
import com.jerboa.feat.VoteType
import com.jerboa.feat.doIfReadyElseDisplayInfo
import com.jerboa.feat.newVote
import com.jerboa.getCommentParentId
import com.jerboa.getDepthFromComment
import com.jerboa.model.AccountViewModel
import com.jerboa.model.PostViewModel
import com.jerboa.model.ReplyItem
import com.jerboa.model.SiteViewModel
import com.jerboa.scrollToNextParentComment
import com.jerboa.scrollToPreviousParentComment
import com.jerboa.ui.components.ban.BanFromCommunityReturn
import com.jerboa.ui.components.ban.BanPersonReturn
import com.jerboa.ui.components.comment.ShowCommentContextButtons
import com.jerboa.ui.components.comment.commentNodeItems
import com.jerboa.ui.components.comment.edit.CommentEditReturn
import com.jerboa.ui.components.comment.reply.CommentReplyReturn
import com.jerboa.ui.components.common.ApiErrorText
import com.jerboa.ui.components.common.CommentNavigationBottomAppBar
import com.jerboa.ui.components.common.CommentSortOptionsDropdown
import com.jerboa.ui.components.common.DualHeaderTitle
import com.jerboa.ui.components.common.JerboaSnackbarHost
import com.jerboa.ui.components.common.LoadingBar
import com.jerboa.ui.components.common.apiErrorToast
import com.jerboa.ui.components.common.getCurrentAccount
import com.jerboa.ui.components.common.isLoading
import com.jerboa.ui.components.common.isRefreshing
import com.jerboa.ui.components.post.edit.PostEditReturn
import com.jerboa.ui.components.remove.comment.CommentRemoveReturn
import com.jerboa.ui.components.remove.post.PostRemoveReturn
import it.vercruysse.lemmyapi.datatypes.BlockPerson
import it.vercruysse.lemmyapi.datatypes.CommentId
import it.vercruysse.lemmyapi.datatypes.CommentView
import it.vercruysse.lemmyapi.datatypes.CreateCommentLike
import it.vercruysse.lemmyapi.datatypes.CreatePostLike
import it.vercruysse.lemmyapi.datatypes.DeleteComment
import it.vercruysse.lemmyapi.datatypes.DeletePost
import it.vercruysse.lemmyapi.datatypes.DistinguishComment
import it.vercruysse.lemmyapi.datatypes.FeaturePost
import it.vercruysse.lemmyapi.datatypes.HidePost
import it.vercruysse.lemmyapi.datatypes.LockPost
import it.vercruysse.lemmyapi.datatypes.PersonView
import it.vercruysse.lemmyapi.datatypes.PostId
import it.vercruysse.lemmyapi.datatypes.PostView
import it.vercruysse.lemmyapi.datatypes.SaveComment
import it.vercruysse.lemmyapi.datatypes.SavePost
import it.vercruysse.lemmyapi.dto.CommentSortType

object PostViewReturn {
    const val POST_VIEW = "post-view::return(post-view)"
}

@ExperimentalLayoutApi
@OptIn(
    ExperimentalMaterial3Api::class,
    ExperimentalComposeUiApi::class,
)
@Composable
fun PostScreen(
    id: Either<PostId, CommentId>,
    siteViewModel: SiteViewModel,
    accountViewModel: AccountViewModel,
    appState: JerboaAppState,
    useCustomTabs: Boolean,
    usePrivateTabs: Boolean,
    showCollapsedCommentContent: Boolean,
    showActionBarByDefault: Boolean,
    showVotingArrowsInListView: Boolean,
    showParentCommentNavigationButtons: Boolean,
    navigateParentCommentsWithVolumeButtons: Boolean,
    blurNSFW: BlurNSFW,
    showPostLinkPreview: Boolean,
    postActionBarMode: PostActionBarMode,
    swipeToActionPreset: SwipeToActionPreset,
    disableVideoAutoplay: Boolean,
) {
    Log.d("jerboa", "got to post screen")

    val ctx = LocalContext.current

    val postViewModel: PostViewModel = viewModel(factory = PostViewModel.Companion.Factory(id))

    appState.ConsumeReturn<PostView>(PostEditReturn.POST_VIEW, postViewModel::updatePost)
    appState.ConsumeReturn<PostView>(PostRemoveReturn.POST_VIEW, postViewModel::updatePost)
    appState.ConsumeReturn<CommentView>(CommentReplyReturn.COMMENT_VIEW, postViewModel::appendComment)
    appState.ConsumeReturn<CommentView>(CommentEditReturn.COMMENT_VIEW, postViewModel::updateComment)
    appState.ConsumeReturn<CommentView>(CommentRemoveReturn.COMMENT_VIEW, postViewModel::updateComment)
    appState.ConsumeReturn<PersonView>(BanPersonReturn.PERSON_VIEW, postViewModel::updateBanned)
    appState.ConsumeReturn<BanFromCommunityData>(
        BanFromCommunityReturn.BAN_DATA_VIEW,
        postViewModel::updateBannedFromCommunity,
    )

    val onClickSortType = { commentSortType: CommentSortType ->
        postViewModel.updateSortType(commentSortType)
        postViewModel.getComments()
    }

    val selectedSortType = postViewModel.sortType

    var showSortOptions by remember { mutableStateOf(false) }
    val focusRequester = remember { FocusRequester() }

    val listState = rememberLazyListState()

    val scrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior(rememberTopAppBarState())
    val scope = rememberCoroutineScope()
    val snackbarHostState = remember { SnackbarHostState() }

    LaunchedEffect(Unit) {
        focusRequester.requestFocus()
    }

    Scaffold(
        snackbarHost = { JerboaSnackbarHost(snackbarHostState) },
        modifier =
            Modifier
                .nestedScroll(scrollBehavior.nestedScrollConnection)
                .semantics { testTagsAsResourceId = true }
                .focusRequester(focusRequester)
                .focusable()
                .onKeyEvent { keyEvent ->
                    if (navigateParentCommentsWithVolumeButtons) {
                        when (keyEvent.key) {
                            Key.VolumeUp -> {
                                scrollToPreviousParentComment(scope, postViewModel.parentListStateIndexes, listState)
                                true
                            }

                            Key.VolumeDown -> {
                                scrollToNextParentComment(scope, postViewModel.parentListStateIndexes, listState)
                                true
                            }

                            else -> {
                                false
                            }
                        }
                    } else {
                        false
                    }
                },
        bottomBar = {
            if (showParentCommentNavigationButtons) {
                CommentNavigationBottomAppBar(
                    scope,
                    postViewModel.parentListStateIndexes,
                    listState,
                )
            }
        },
        topBar = {
            Column {
                TopAppBar(
                    title = {
                        DualHeaderTitle(
                            topText = stringResource(R.string.post_screen_comments),
                            bottomText = getLocalizedCommentSortTypeName(ctx, selectedSortType),
                        )
                    },
                    navigationIcon = {
                        IconButton(
                            modifier = Modifier.testTag("jerboa:back"),
                            onClick = appState::navigateUp,
                        ) {
                            Icon(
                                Icons.AutoMirrored.Outlined.ArrowBack,
                                contentDescription = stringResource(R.string.topAppBar_back),
                            )
                        }
                    },
                    actions = {
                        Box {
                            IconButton(onClick = {
                                showSortOptions = true
                            }) {
                                Icon(
                                    Icons.AutoMirrored.Outlined.Sort,
                                    contentDescription = stringResource(R.string.selectSort),
                                )
                            }

                            CommentSortOptionsDropdown(
                                expanded = showSortOptions,
                                selectedSortType = selectedSortType,
                                onDismissRequest = { showSortOptions = false },
                                onClickSortType = onClickSortType,
                            )
                        }
                    },
                    scrollBehavior = scrollBehavior,
                )
            }
        },
        content = { padding ->
            PullToRefreshBox(
                modifier = Modifier
                    .padding(padding)
                    .fillMaxWidth(),
                isRefreshing = postViewModel.postRes.isRefreshing(),
                onRefresh = {
                    postViewModel.getData(ApiState.Refreshing)
                },
            ) {
                MainPostScreenBody(
                    id = id,
                    postViewModel = postViewModel,
                    siteViewModel = siteViewModel,
                    accountViewModel = accountViewModel,
                    appState = appState,
                    listState = listState,
                    snackbarHostState = snackbarHostState,
                    useCustomTabs = useCustomTabs,
                    usePrivateTabs = usePrivateTabs,
                    showCollapsedCommentContent = showCollapsedCommentContent,
                    showActionBarByDefault = showActionBarByDefault,
                    showVotingArrowsInListView = showVotingArrowsInListView,
                    blurNSFW = blurNSFW,
                    showPostLinkPreview = showPostLinkPreview,
                    postActionBarMode = postActionBarMode,
                    swipeToActionPreset = swipeToActionPreset,
                    disableVideoAutoplay = disableVideoAutoplay,
                )
            }
        },
    )
}

@OptIn(ExperimentalLayoutApi::class)
@Composable
fun MainPostScreenBody(
    id: Either<PostId, CommentId>,
    postViewModel: PostViewModel,
    siteViewModel: SiteViewModel,
    accountViewModel: AccountViewModel,
    appState: JerboaAppState,
    listState: LazyListState,
    snackbarHostState: SnackbarHostState,
    useCustomTabs: Boolean,
    usePrivateTabs: Boolean,
    showCollapsedCommentContent: Boolean,
    showActionBarByDefault: Boolean,
    showVotingArrowsInListView: Boolean,
    blurNSFW: BlurNSFW,
    showPostLinkPreview: Boolean,
    postActionBarMode: PostActionBarMode,
    swipeToActionPreset: SwipeToActionPreset,
    disableVideoAutoplay: Boolean,
) {
    val ctx = LocalContext.current
    val scope = rememberCoroutineScope()

    val commentsWithToggledActionBar = postViewModel.commentsWithToggledActionBar
    val account = getCurrentAccount(accountViewModel = accountViewModel)

    postViewModel.parentListStateIndexes.clear()
    var lazyListIndexTracker = 2
    when (val postRes = postViewModel.postRes) {
        is ApiState.Loading -> {
            LoadingBar()
        }

        is ApiState.Failure -> {
            ApiErrorText(postRes.msg)
        }

        is ApiState.Success -> {
            val postView = postRes.data.post_view
            val moderators = remember(postRes) { postRes.data.moderators.map { it.moderator.id } }

            if (!account.isAnon()) {
                appState.addReturn(
                    PostViewReturn.POST_VIEW,
                    postView.copy(read = true),
                )
            }
            LazyColumn(
                state = listState,
                modifier = Modifier.testTag("jerboa:comments"),
            ) {
                item(key = "${postView.post.id}_listing", "post_listing") {
                    PostListing(
                        postView = postView,
                        admins = siteViewModel.admins(),
                        moderators = moderators,
                        onUpvoteClick = { pv ->
                            account.doIfReadyElseDisplayInfo(
                                appState,
                                ctx,
                                snackbarHostState,
                                scope,
                                siteViewModel,
                                accountViewModel,
                            ) {
                                postViewModel.likePost(
                                    CreatePostLike(
                                        post_id = pv.post.id,
                                        score = newVote(pv.my_vote, VoteType.Upvote),
                                    ),
                                )
                            }
                        },
                        onDownvoteClick = { pv ->
                            account.doIfReadyElseDisplayInfo(
                                appState,
                                ctx,
                                snackbarHostState,
                                scope,
                                siteViewModel,
                                accountViewModel,
                            ) {
                                postViewModel.likePost(
                                    CreatePostLike(
                                        post_id = pv.post.id,
                                        score = newVote(pv.my_vote, VoteType.Downvote),
                                    ),
                                )
                            }
                        },
                        onReplyClick = { pv ->
                            appState.toCommentReply(
                                replyItem = ReplyItem.PostItem(pv),
                            )
                        },
                        onPostClick = {},
                        onSaveClick = { pv ->
                            account.doIfReadyElseDisplayInfo(
                                appState,
                                ctx,
                                snackbarHostState,
                                scope,
                                siteViewModel,
                                accountViewModel,
                            ) {
                                postViewModel.savePost(
                                    SavePost(
                                        post_id = pv.post.id,
                                        save = !pv.saved,
                                    ),
                                )
                            }
                        },
                        onCommunityClick = { community ->
                            appState.toCommunity(id = community.id)
                        },
                        onEditPostClick = { pv ->
                            appState.toPostEdit(
                                postView = pv,
                            )
                        },
                        onDeletePostClick = { pv ->
                            account.doIfReadyElseDisplayInfo(
                                appState,
                                ctx,
                                snackbarHostState,
                                scope,
                                siteViewModel,
                                accountViewModel,
                            ) {
                                postViewModel.deletePost(
                                    DeletePost(
                                        post_id = pv.post.id,
                                        deleted = !pv.post.deleted,
                                    ),
                                )
                            }
                        },
                        onHidePostClick = { pv ->
                            account.doIfReadyElseDisplayInfo(
                                appState,
                                ctx,
                                snackbarHostState,
                                scope,
                                siteViewModel,
                                accountViewModel,
                            ) {
                                postViewModel.hidePost(
                                    HidePost(
                                        post_ids = listOf(pv.post.id),
                                        hide = !pv.hidden,
                                    ),
                                    ctx,
                                )
                            }
                        },
                        onReportClick = { pv ->
                            appState.toPostReport(id = pv.post.id)
                        },
                        onRemoveClick = { pv ->
                            appState.toPostRemove(post = pv.post)
                        },
                        onBanPersonClick = { p ->
                            appState.toBanPerson(person = p)
                        },
                        onBanFromCommunityClick = { d ->
                            appState.toBanFromCommunity(banData = d)
                        },
                        onLockPostClick = { pv ->
                            account.doIfReadyElseDisplayInfo(
                                appState,
                                ctx,
                                snackbarHostState,
                                scope,
                                siteViewModel,
                                accountViewModel,
                            ) {
                                postViewModel.lockPost(
                                    LockPost(
                                        post_id = pv.post.id,
                                        locked = !pv.post.locked,
                                    ),
                                )
                            }
                        },
                        onFeaturePostClick = { data ->
                            account.doIfReadyElseDisplayInfo(
                                appState,
                                ctx,
                                snackbarHostState,
                                scope,
                                siteViewModel,
                                accountViewModel,
                            ) {
                                postViewModel.featurePost(
                                    FeaturePost(
                                        post_id = data.post.id,
                                        featured = !data.featured,
                                        feature_type = data.type,
                                    ),
                                )
                            }
                        },
                        onViewVotesClick = appState::toPostLikes,
                        onPersonClick = appState::toProfile,
                        // Do nothing
                        showReply = true,
                        fullBody = true,
                        account = account,
                        postViewMode = PostViewMode.SmallCard,
                        enableDownVotes = siteViewModel.enableDownvotes(),
                        showAvatar = siteViewModel.showAvatar(),
                        showVotingArrowsInListView = showVotingArrowsInListView,
                        useCustomTabs = useCustomTabs,
                        usePrivateTabs = usePrivateTabs,
                        blurNSFW = blurNSFW,
                        appState = appState,
                        showPostLinkPreview = showPostLinkPreview,
                        showIfRead = false,
                        voteDisplayMode = siteViewModel.voteDisplayMode(),
                        postActionBarMode = postActionBarMode,
                        swipeToActionPreset = swipeToActionPreset,
                        disableVideoAutoplay = disableVideoAutoplay,
                    )
                }

                if (postViewModel.commentsRes.isLoading()) {
                    item(contentType = "loadingbar") {
                        LoadingBar()
                    }
                }

                item(contentType = "horizontalDivider") {
                    HorizontalDivider()
                }

                when (val commentsRes = postViewModel.commentsRes) {
                    is ApiState.Failure -> {
                        item(key = "error") {
                            apiErrorToast(
                                ctx,
                                commentsRes.msg,
                            )
                        }
                    }

                    is ApiState.Holder -> {
                        val commentTree =
                            buildCommentsTree(
                                commentsRes.data.comments,
                                id.fold(
                                    { null },
                                    { it },
                                ),
                            )

                        item(
                            key = "${postView.post.id}_is_comment_view",
                            contentType = "contextButtons",
                        ) {
                            if (postViewModel.isCommentView()) {
                                val firstCommentNodeData = commentTree.firstOrNull()

                                val firstCommentPath = firstCommentNodeData?.getPath()

                                val hasParent =
                                    firstCommentPath != null &&
                                        getDepthFromComment(
                                            firstCommentPath,
                                        ) > 0

                                val commentParentId =
                                    firstCommentPath?.let(::getCommentParentId)

                                ShowCommentContextButtons(
                                    postView.post.id,
                                    commentParentId = commentParentId,
                                    showContextButton = hasParent,
                                    onPostClick = appState::toPost,
                                    onCommentClick = appState::toComment,
                                )
                            }
                        }

                        commentNodeItems(
                            nodes = commentTree,
                            admins = siteViewModel.admins(),
                            moderators = moderators,
                            increaseLazyListIndexTracker = {
                                lazyListIndexTracker++
                            },
                            addToParentIndexes = {
                                postViewModel.parentListStateIndexes.add(lazyListIndexTracker)
                            },
                            isFlat = false,
                            isExpanded = postViewModel::isExpanded,
                            toggleExpanded = postViewModel::toggleExpanded,
                            toggleActionBar = postViewModel::toggleActionBar,
                            onMarkAsReadClick = {},
                            onCommentClick = postViewModel::toggleExpanded,
                            onUpvoteClick = { cv ->
                                account.doIfReadyElseDisplayInfo(
                                    appState,
                                    ctx,
                                    snackbarHostState,
                                    scope,
                                    siteViewModel,
                                    accountViewModel,
                                ) {
                                    postViewModel.likeComment(
                                        CreateCommentLike(
                                            comment_id = cv.comment.id,
                                            score = newVote(
                                                cv.my_vote,
                                                VoteType.Upvote,
                                            ),
                                        ),
                                    )
                                }
                            },
                            onDownvoteClick = { cv ->
                                account.doIfReadyElseDisplayInfo(
                                    appState,
                                    ctx,
                                    snackbarHostState,
                                    scope,
                                    siteViewModel,
                                    accountViewModel,
                                ) {
                                    postViewModel.likeComment(
                                        CreateCommentLike(
                                            comment_id = cv.comment.id,
                                            score = newVote(
                                                cv.my_vote,
                                                VoteType.Downvote,
                                            ),
                                        ),
                                    )
                                }
                            },
                            onReplyClick = { cv ->
                                appState.toCommentReply(
                                    replyItem = ReplyItem.CommentItem(cv),
                                )
                            },
                            onSaveClick = { cv ->
                                account.doIfReadyElseDisplayInfo(
                                    appState,
                                    ctx,
                                    snackbarHostState,
                                    scope,
                                    siteViewModel,
                                    accountViewModel,
                                ) {
                                    postViewModel.saveComment(
                                        SaveComment(
                                            comment_id = cv.comment.id,
                                            save = !cv.saved,
                                        ),
                                    )
                                }
                            },
                            onPersonClick = appState::toProfile,
                            onViewVotesClick = appState::toCommentLikes,
                            onHeaderClick = postViewModel::toggleExpanded,
                            onHeaderLongClick = postViewModel::toggleActionBar,
                            onEditCommentClick = appState::toCommentEdit,
                            onDeleteCommentClick = { cv ->
                                account.doIfReadyElseDisplayInfo(
                                    appState,
                                    ctx,
                                    snackbarHostState,
                                    scope,
                                    siteViewModel,
                                    accountViewModel,
                                ) {
                                    postViewModel.deleteComment(
                                        DeleteComment(
                                            comment_id = cv.comment.id,
                                            deleted = !cv.comment.deleted,
                                        ),
                                    )
                                }
                            },
                            onDistinguishClick = { cv ->
                                account.doIfReadyElseDisplayInfo(
                                    appState,
                                    ctx,
                                    snackbarHostState,
                                    scope,
                                    siteViewModel,
                                    accountViewModel,
                                ) {
                                    postViewModel.distinguishComment(
                                        DistinguishComment(
                                            comment_id = cv.comment.id,
                                            distinguished = !cv.comment.distinguished,
                                        ),
                                    )
                                }
                            },
                            onReportClick = { cv ->
                                appState.toCommentReport(id = cv.comment.id)
                            },
                            onRemoveClick = { cv ->
                                appState.toCommentRemove(comment = cv.comment)
                            },
                            onBanPersonClick = appState::toBanPerson,
                            onBanFromCommunityClick = appState::toBanFromCommunity,
                            onCommentLinkClick = { cv ->
                                appState.toComment(id = cv.comment.id)
                            },
                            onFetchChildrenClick = postViewModel::fetchMoreChildren,
                            onBlockCreatorClick = { person ->
                                account.doIfReadyElseDisplayInfo(
                                    appState,
                                    ctx,
                                    snackbarHostState,
                                    scope,
                                    siteViewModel,
                                    accountViewModel,
                                ) {
                                    postViewModel.blockPerson(
                                        BlockPerson(
                                            person_id = person.id,
                                            block = true,
                                        ),
                                        ctx,
                                    )
                                }
                            },
                            onCommunityClick = { community ->
                                appState.toCommunity(id = community.id)
                            },
                            // Do nothing
                            onPostClick = {},
                            account = account,
                            enableDownVotes = siteViewModel.enableDownvotes(),
                            showAvatar = siteViewModel.showAvatar(),
                            isCollapsedByParent = false,
                            showCollapsedCommentContent = showCollapsedCommentContent,
                            showActionBar = { commentId ->
                                showActionBarByDefault xor
                                    commentsWithToggledActionBar.contains(
                                        commentId,
                                    )
                            },
                            blurNSFW = blurNSFW,
                            voteDisplayMode = siteViewModel.voteDisplayMode(),
                            swipeToActionPreset = swipeToActionPreset,
                        )
                        item {
                            Spacer(modifier = Modifier.height(100.dp))
                        }
                    }

                    else -> {}
                }
            }
        }

        else -> {}
    }
}
